package org.veridiandynamics.server.dao;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.veridiandynamics.server.domain.Admin;
import org.veridiandynamics.server.domain.Appointment;
import org.veridiandynamics.server.domain.Doctor;
import org.veridiandynamics.server.domain.DoctorsOrders;
import org.veridiandynamics.server.domain.Event;
import org.veridiandynamics.server.domain.Invoice;
import org.veridiandynamics.server.domain.MyException;
import org.veridiandynamics.server.domain.Nurse;
import org.veridiandynamics.server.domain.Patient;
import org.veridiandynamics.server.domain.PersistObject;
import org.veridiandynamics.server.domain.Roles;
import org.veridiandynamics.server.domain.Schedule;
import org.veridiandynamics.server.domain.ServicesBillable;
import org.veridiandynamics.server.domain.TreatmentRecord;

/**
 * Driver class for Hibernate Database
 *
 *
 */
public class HibernateDriver {
	
	private SessionFactory sessionFactory;
	
	/**
	 * Constructor for database; creates new session.
	 */
	public HibernateDriver()
	{
	    sessionFactory = new Configuration().configure().buildSessionFactory();
	}
	
	/**
	 * Saves object to database.
	 * 
	 * @param myObject Object to be saved
	 */
	public void SaveObject(PersistObject myObject)
	{
		
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		session.save(myObject);
		session.getTransaction().commit();
		session.close();		
	}
	
	/**
	 * Deletes object from database 
	 * @param myObject Object to be deleted.
	 */
	public void DeleteObject(PersistObject myObject)
	{
		Session session = sessionFactory.openSession();
        session.beginTransaction();
        session.delete(myObject);
        session.getTransaction().commit();
        session.close();
		
		
	}
	
	/**
	 * Returns object stored in database when called. 
	 * 
	 * @param ID long variable storing id for Object requested.
	 * @param myObject Object requested 
	 * @return Object the object that was requested is returned if found
	 */
	public Object RetrieveObject(long id, PersistObject myObject)
	{
		Session session = sessionFactory.openSession();
        session.beginTransaction();

        
        if(myObject instanceof Patient)
        {
        Object returnobject;
        returnobject=session.get(Patient.class, id);
        session.close();
		return returnobject;
        } 
        else if(myObject instanceof Admin)
        {
            Object returnobject;
            returnobject=session.get(Admin.class, id);
            session.close();
    		return returnobject;        	
        }
        else if(myObject instanceof Appointment)
        {
            Object returnobject;
            returnobject=session.get(Appointment.class, id);
            session.close();
    		return returnobject;        	
        }
        else if(myObject instanceof Doctor)
        {
            Object returnobject;
            returnobject=session.get(Doctor.class, id);
            session.close();
    		return returnobject;        	
        }
        else if(myObject instanceof DoctorsOrders)
        {
            Object returnobject;
            returnobject=session.get(DoctorsOrders.class, id);
            session.close();
    		return returnobject;        	
        }
        else if(myObject instanceof Invoice)
        {
            Object returnobject;
            returnobject=session.get(Invoice.class, id);
            session.close();
    		return returnobject;        	
        }   
        else if(myObject instanceof Nurse)
        {
            Object returnobject;
            returnobject=session.get(Nurse.class, id);
            session.close();
    		return returnobject;        	
        }    
        else if(myObject instanceof Schedule)
        {
            Object returnobject;
            returnobject=session.get(Schedule.class, id);
            session.close();
    		return returnobject;        	
        }    
        else if(myObject instanceof TreatmentRecord)
        {
            Object returnobject;
            returnobject=session.get(TreatmentRecord.class, id);
            session.close();
    		return returnobject;        	
        }    
        else if (myObject instanceof Event)
        {
            Object returnobject;
            returnobject=session.get(Event.class, id);
            session.close();
    		return returnobject;        	
        }        	
        else
        {
        	Object returnobject=null;
        	session.close();
        	return returnobject;
        } 
        
	}

	/**
	 * This will modify a currently existing object.
	 * 
	 * @param myObject Object to be updated.
	 */
	public void UpdateObject(PersistObject myObject)
	{
		
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		session.update(myObject);
		session.getTransaction().commit();
		session.close();		
	}

	
	/**
	 * Will return all instances stored of a particular type of object.
	 * 
	 * @param myObject type of object requested
	 * @return current list of objects requested 
	 */
	public List GetAll(PersistObject myObject)
	{
		
		Session session=sessionFactory.openSession();
        session.beginTransaction();
        List result=null;

        if(myObject instanceof Patient)
        {
            result = session.createQuery( "from Patient" ).list();
        } 
        else if(myObject instanceof Admin)
        {
            result = session.createQuery( "from Admin" ).list();    
        }
        else if(myObject instanceof Event)
        {
            result = session.createQuery( "from Event" ).list();    
        }

        else if(myObject instanceof Appointment)
        {
            result = session.createQuery( "from Appointment" ).list();
        }
        else if(myObject instanceof Doctor)
        {
            result = session.createQuery( "from Doctor" ).list(); 
        }
        else if(myObject instanceof DoctorsOrders)
        {
            result = session.createQuery( "from DoctorsOrders" ).list();       	
        }
        else if(myObject instanceof Invoice)
        {
         result = session.createQuery( "from Invoice" ).list();
        }   
        else if(myObject instanceof Nurse)
        {
           result = session.createQuery( "from Nurse" ).list();
        }    
        else if(myObject instanceof Schedule)
        {
           result = session.createQuery( "from Schedule" ).list();
        }    
        else if(myObject instanceof TreatmentRecord)
        {
            result = session.createQuery( "from TreatmentRecord" ).list();    
        } 
        else if(myObject instanceof ServicesBillable)
        {
            result = session.createQuery( "from ServicesBillable" ).list();    
        }         
        else if(myObject instanceof Roles)
        {
            result = session.createQuery( "from Roles" ).list();    
        } else if(myObject instanceof MyException)
        {
            result = session.createQuery( "from MyException" ).list();    
        }   
        session.getTransaction().commit();
        session.close();
        return result;
	} 
	
	//Take in username, password, and a role object, return an object that needs to be casted to the right class.
	/**
	 * Returns object representing user that is currently logged in.
	 * 
	 * @param username
	 * @param password 
	 * @param role The role the user would like to log in as.
	 * @return user object that is currently logged in.
	 */
	public Object LoginRetrieve(String username, String password, Roles role)
	{
		
		Object result=null;
		List idresult;
		idresult=Queryprocessor.IdQuery("SELECT * FROM USER INNER JOIN USER_ROLE ON USER.uid = USER_ROLE.uid INNER JOIN ROLES ON ROLES.RID= USER_ROLE.RID WHERE USERNAME='"+username+"' AND PASSWORD='"+password+"' AND ROLE='"+Integer.toString(role.getRole())+"'");
		if(!(idresult.isEmpty())){
			if(role.getRole()==10){
				Patient logdummy=new Patient();
				return RetrieveObject(Queryprocessor.UsernametoID(username), logdummy);
			} else 	if(role.getRole()==20){
				Nurse logdummy=new Nurse();
				return RetrieveObject(Queryprocessor.UsernametoID(username), logdummy);
			} else 	if(role.getRole()==30){
				Doctor logdummy=new Doctor();
				return RetrieveObject(Queryprocessor.UsernametoID(username), logdummy);
			} else {
				Admin logdummy=new Admin();
				return RetrieveObject(Queryprocessor.UsernametoID(username), logdummy);				
			}

		} else {return result;}
		
	}
	
	public void CloseConnection()
	{
		sessionFactory.close();
	}
	
	
}
